/*
 *
 *  MIT License
 *
 *  Copyright (c) 2017 Alibaba Group
 *
 *  Permission is hereby granted, free of charge, to any person obtaining a copy
 *  of this software and associated documentation files (the "Software"), to deal
 *  in the Software without restriction, including without limitation the rights
 *  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 *  copies of the Software, and to permit persons to whom the Software is
 *  furnished to do so, subject to the following conditions:
 *
 *  The above copyright notice and this permission notice shall be included in all
 *  copies or substantial portions of the Software.
 *
 *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 *  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 *  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 *  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 *  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 *  SOFTWARE.
 *
 */

package com.tmall.ultraviewpager;


import ohos.agp.components.*;

import ohos.agp.utils.Point;
import ohos.agp.window.service.Display;
import ohos.agp.window.service.DisplayAttributes;
import ohos.agp.window.service.DisplayManager;
import ohos.app.Context;
import ohos.media.image.PixelMap;
import ohos.multimodalinput.event.TouchEvent;
import ohos.utils.PlainIntArray;

import java.util.Optional;


/**
 * 带指示器的滑动切换页面
 */
public class UltraViewPager extends DependentLayout implements IUltraViewPagerFeature, Component.TouchEventListener, ComponentTreeObserver.WindowBoundListener {
    private static final String UPV_AUTOSCROLL = "upv_autoscroll";
    private static final String UPV_INFINITELOOP = "upv_infiniteloop";
    private static final String UPV_RATIO = "upv_ratio";
    private static final String UPV_SCROLLMODE = "upv_scrollmode";
    private static final String UPV_DISABLESCROLL = "upv_disablescroll";
    private static final String UPV_MULTISCREEN = "upv_multiscreen";
    private static final String UPV_AUTOMEASURE = "upv_automeasure";
    private static final String UPV_ITEMRATIO = "upv_itemratio";
    private int mAutoScrollValue = 0;
    private boolean mInfiniteloop = false;
    private float mRatio = Float.NaN;
    private int mScrollMode = 0;
    private int mDisableScroll = 0;
    private float mMultiscreen = 1f;
    private boolean mAutoMeasure = false;
    private float mItemRatio = Float.NaN;

    /**
     * 窗口获取焦点
     */
    @Override
    public void onWindowBound() {

    }

    /**
     * 窗口失去焦点
     */
    @Override
    public void onWindowUnbound() {
        stopTimer();
    }


    /**
     * 滑动类型
     */
    public enum ScrollMode {
        HORIZONTAL(0), VERTICAL(1);
        int id;

        ScrollMode(int id) {
            this.id = id;
        }

        static ScrollMode getScrollMode(int id) {
            for (ScrollMode scrollMode : values()) {
                if (scrollMode.id == id) {
                    return scrollMode;
                }
            }
            throw new IllegalArgumentException();
        }
    }

    /**
     * 滑动方向类
     */
    public enum Orientation {
        HORIZONTAL, VERTICAL
    }

    /**
     * 滑动方向
     */
    public enum ScrollDirection {
        NONE(0), BACKWARD(1), FORWARD(2);
        int id;

        ScrollDirection(int id) {
            this.id = id;
        }

        static ScrollDirection getScrollDirection(int id) {
            for (ScrollDirection direction : values()) {
                if (direction.id == id) {
                    return direction;
                }
            }
            throw new IllegalArgumentException();
        }
    }

    private final Point size;
    private final Point maxSize;

    private float ratio = Float.NaN;

    // Maximum width of child when enable multiScreen.
    private int maxWidth = -1;

    // Maximum height of child when enable multiScreen.
    private int maxHeight = -1;

    private UltraViewPagerView viewPager;
    private UltraViewPagerIndicator pagerIndicator;

    private TimerHandler timer;

    public UltraViewPager(Context context) {
        super(context);
        size = new Point();
        maxSize = new Point();
        initView();
    }

    public UltraViewPager(Context context, AttrSet attrs) {
        super(context, attrs);
        size = new Point();
        maxSize = new Point();
        initView();
        initView(context, attrs);
    }

    public UltraViewPager(Context context, AttrSet attrs, String styleName) {
        super(context, attrs, styleName);
        size = new Point();
        maxSize = new Point();
        initView();
    }

    private void initView() {
        viewPager = new UltraViewPagerView(getContext());

        addComponent(viewPager, new ComponentContainer.LayoutConfig(ComponentContainer.LayoutConfig.MATCH_PARENT, ComponentContainer.LayoutConfig.MATCH_PARENT));

    }

    private void initView(Context context, AttrSet attrs) {

        boolean presentAutoScroll = attrs.getAttr(UPV_AUTOSCROLL).isPresent();
        if (presentAutoScroll) {

            mAutoScrollValue = attrs.getAttr(UPV_AUTOSCROLL).get().getIntegerValue();

            setAutoScroll(mAutoScrollValue);
        }
        boolean presentInfiniteloop = attrs.getAttr(UPV_INFINITELOOP).isPresent();
        if (presentInfiniteloop) {

            mInfiniteloop = attrs.getAttr(UPV_INFINITELOOP).get().getBoolValue();

            setInfiniteLoop(mInfiniteloop);
        }
        boolean presentRatio = attrs.getAttr(UPV_RATIO).isPresent();
        if (presentRatio) {
            mRatio = attrs.getAttr(UPV_RATIO).get().getFloatValue();
            setRatio(mRatio);
        }
        boolean presentScrollMode = attrs.getAttr(UPV_SCROLLMODE).isPresent();
        if (presentScrollMode) {
            mScrollMode = attrs.getAttr(UPV_SCROLLMODE).get().getIntegerValue();
            setScrollMode(ScrollMode.getScrollMode(mScrollMode));
        }

        boolean presentDisableScroll = attrs.getAttr(UPV_DISABLESCROLL).isPresent();
        if (presentDisableScroll) {
            mDisableScroll = attrs.getAttr(UPV_DISABLESCROLL).get().getIntegerValue();
            disableScrollDirection(ScrollDirection.getScrollDirection(mDisableScroll));
        }
        boolean presentMultiscreen = attrs.getAttr(UPV_MULTISCREEN).isPresent();
        if (presentMultiscreen) {
            mMultiscreen = attrs.getAttr(UPV_MULTISCREEN).get().getFloatValue();
            setMultiScreen(mMultiscreen);
        }
        boolean presentAutoMeasure = attrs.getAttr(UPV_AUTOMEASURE).isPresent();
        if (presentAutoMeasure) {
            mAutoMeasure = attrs.getAttr(UPV_AUTOMEASURE).get().getBoolValue();
            setAutoMeasureHeight(mAutoMeasure);
        }
        boolean presentItemRatio = attrs.getAttr(UPV_ITEMRATIO).isPresent();
        if (presentItemRatio) {
            mItemRatio = attrs.getAttr(UPV_ITEMRATIO).get().getFloatValue();
            setItemRatio(mItemRatio);
        }


    }


    /**
     * 是否绑定到当前窗口
     *
     * @return boolean 是否获取焦点
     */
    @Override
    public boolean isBoundToWindow() {
        if (super.isBoundToWindow()) {
            startTimer();
        }
        return super.isBoundToWindow();
    }

    /**
     * 触摸事件处理
     *
     * @param component  触摸控件
     * @param touchEvent 触摸事件
     * @return 返回状态
     */
    @Override
    public boolean onTouchEvent(Component component, TouchEvent touchEvent) {
        if (timer != null) {
            final int action = touchEvent.getAction();
            if (action == TouchEvent.PRIMARY_POINT_DOWN) {
                stopTimer();
            }
            if (action == TouchEvent.PRIMARY_POINT_UP || action == TouchEvent.CANCEL) {
                startTimer();
            }
        }
        return false;


    }

    /**
     * 初始化指示器构建类
     *
     * @return 指示器构建类
     */
    @Override
    public IUltraIndicatorBuilder initIndicator() {
        disableIndicator();
        pagerIndicator = new UltraViewPagerIndicator(getContext());
        pagerIndicator.setViewPager(viewPager);
        pagerIndicator.setIndicatorBuildListener(new UltraViewPagerIndicator.UltraViewPagerIndicatorListener() {
            @Override
            public void build() {
                removeComponent(pagerIndicator);
                addComponent(pagerIndicator, new DependentLayout.LayoutConfig(ComponentContainer.LayoutConfig.MATCH_PARENT, ComponentContainer.LayoutConfig.MATCH_PARENT));
            }
        });
        return pagerIndicator;
    }

    @Override
    public IUltraIndicatorBuilder initIndicator(int focusColor, int normalColor, int radiusInPixel, int gravity) {
        return initIndicator()
                .setFocusColor(focusColor)
                .setNormalColor(normalColor)
                .setRadius(radiusInPixel)
                .setGravity(gravity);
    }

    @Override
    public IUltraIndicatorBuilder initIndicator(int focusColor, int normalColor, int strokeColor, int strokeWidth, int radiusInPixel, int gravity) {
        return initIndicator()
                .setFocusColor(focusColor)
                .setNormalColor(normalColor)
                .setStrokeWidth(strokeWidth)
                .setStrokeColor(strokeColor)
                .setRadius(radiusInPixel)
                .setGravity(gravity);
    }

    @Override
    public IUltraIndicatorBuilder initIndicator(int focusResId, int normalResId, int gravity) {
        return initIndicator()
                .setFocusResId(focusResId)
                .setNormalResId(normalResId)
                .setGravity(gravity);
    }

    @Override
    public IUltraIndicatorBuilder initIndicator(PixelMap focusBitmap, PixelMap normalBitmap, int gravity) {
        return initIndicator()
                .setFocusIcon(focusBitmap)
                .setNormalIcon(normalBitmap)
                .setGravity(gravity);
    }


    @Override
    public void disableIndicator() {
        if (pagerIndicator != null) {
            removeComponent(pagerIndicator);
            pagerIndicator = null;
        }
    }

    /**
     * 获取指示器构建类
     *
     * @return 指示器构建类
     */
    public IUltraIndicatorBuilder getIndicator() {
        return pagerIndicator;
    }

    private TimerHandler.TimerHandlerListener mTimerHandlerListener = new TimerHandler.TimerHandlerListener() {
        @Override
        public int getNextItem() {
            return UltraViewPager.this.getNextItem();
        }

        @Override
        public void callBack() {
            scrollNextPage();
        }
    };

    @Override
    public void setAutoScroll(int intervalInMillis) {

        if (0 == intervalInMillis) {
            return;
        }
        if (timer != null) {
            disableAutoScroll();
        }
        timer = new TimerHandler(mTimerHandlerListener, (long) intervalInMillis);
        startTimer();
    }

    @Override
    public void setAutoScroll(int intervalInMillis, PlainIntArray intervalArray) {
        if (0 == intervalInMillis) {
            return;
        }
        if (timer != null) {
            disableAutoScroll();
        }
        timer = new TimerHandler(mTimerHandlerListener, (long) intervalInMillis);
        timer.specialInterval = intervalArray;
        startTimer();
    }

    @Override
    public void disableAutoScroll() {
        stopTimer();
        timer = null;
    }

    @Override
    public void setScrollMode(ScrollMode scrollMode) {
        viewPager.setScrollMode(scrollMode);
    }

    @Override
    public void setInfiniteLoop(boolean enableLoop) {
        viewPager.setEnableLoop(enableLoop);
    }

    @Override
    public void setMaxWidth(int width) {
        maxWidth = width;
    }

    @Override
    public void setRatio(float ratio) {
        this.ratio = ratio;
        viewPager.setRatio(ratio);
    }

    @Override
    public void setHGap(int pixel) {
        Optional<Display> defaultDisplay = DisplayManager.getInstance().getDefaultDisplay(getContext());
        if (defaultDisplay.isPresent()) {
            Display display = defaultDisplay.get();
            DisplayAttributes attributes = display.getAttributes();
            int screenWidth = attributes.width;
            viewPager.setMultiScreen((screenWidth - pixel) / (float) screenWidth);


        }


    }

    @Override
    public void setMaxHeight(int height) {
        maxHeight = height;
    }

    @Override
    public void disableScrollDirection(ScrollDirection direction) {

    }

    @Override
    public boolean scrollLastPage() {
        boolean isChange = false;
        if (viewPager != null && viewPager.getProvider() != null && viewPager.getProvider().getCount() > 0) {
            final int curr = viewPager.getCurrentItemFake();
            int lastPage = 0;
            if (curr > 0) {
                lastPage = curr - 1;
                isChange = true;
            }
            viewPager.setCurrentItemFake(lastPage, true);
        }
        return isChange;
    }

    @Override
    public boolean scrollNextPage() {
        boolean isChange = false;
        if (viewPager != null && viewPager.getProvider() != null && viewPager.getProvider().getCount() > 0) {
            final int curr = viewPager.getCurrentItemFake();
            int nextPage = 0;
            if (curr < viewPager.getProvider().getCount() - 1) {
                nextPage = curr + 1;
                isChange = true;
            }
            viewPager.setCurrentItemFake(nextPage, true);
        }
        return isChange;
    }

    @Override
    public void setMultiScreen(float ratio) {
        if (ratio <= 0 || ratio > 1) {
            throw new IllegalArgumentException("");
        }
        if (ratio <= 1f) {
            viewPager.setMultiScreen(ratio);
        }
    }

    @Override
    public void setAutoMeasureHeight(boolean status) {
        viewPager.setAutoMeasureHeight(status);
    }

    @Override
    public void setItemRatio(double ratio) {
        viewPager.setItemRatio(ratio);
    }

    @Override
    public void setItemMargin(int left, int top, int right, int bottom) {
        viewPager.setItemMargin(left, top, right, bottom);
    }

    @Override
    public void setScrollMargin(int left, int right) {
        viewPager.setPadding(left, 0, right, 0);
    }


    /**
     * 设置滑动适配器
     *
     * @param adapter 滑动适配器
     */
    public void setProvider(PageSliderProvider adapter) {
        viewPager.setProvider(adapter);
    }

    /**
     * 设置屏幕显示个数
     *
     * @param limit 限制屏幕显示个数
     */
    public void setOffscreenPageLimit(int limit) {
        viewPager.setPageCacheSize(limit);
    }

    /**
     * 获取滑动适配器
     *
     * @return 滑动适配器
     */
    public PageSliderProvider getAdapter() {
        return viewPager.getProvider() == null ? null : ((UltraViewPagerAdapter) viewPager.getProvider()).getAdapter();
    }

    /**
     * 获取适配器
     *
     * @return 获取包裹的适配器
     */
    public PageSliderProvider getWrapAdapter() {
        return viewPager.getProvider();
    }

    /**
     * 刷新数据
     */
    public void refresh() {
        if (viewPager.getProvider() != null) {
            viewPager.getProvider().notifyDataChanged();
        }
    }

    /**
     * 设置滑动页面监听
     *
     * @param listener 页面滑动监听
     */
    public void setOnPageChangeListener(PageSlider.PageChangedListener listener) {
        if (pagerIndicator == null) {
            //avoid registering the same listener twice
            viewPager.removePageChangedListener(listener);
            viewPager.addPageChangedListener(listener);
        } else {
            pagerIndicator.setPageChangeListener(listener);
        }
    }

    /**
     * 设置当前页面
     *
     * @param item 当前页面索引
     */
    public void setCurrentItem(int item) {
        viewPager.setCurrentPage(item);
    }

    /**
     * 设置当前页面
     * @param item 当前页面索引
     * @param smoothScroll 是否平滑滑动
     */
    public void setCurrentItem(int item, boolean smoothScroll) {
        viewPager.setCurrentPage(item, smoothScroll);
    }

    /**
     * 获取当前页面索引
     *
     * @return 获取当前页面索引
     */
    public int getCurrentItem() {
        return viewPager.getCurrentPage();
    }

    /**
     * 获取下一页
     *
     * @return 获取下一个页面
     */
    public int getNextItem() {
        return viewPager.getNextItem();
    }

    public void setPageTransformer(boolean reverseDrawingOrder, PageSlider.ComponentStateChangedListener transformer) {

    }

    public UltraViewPagerView getViewPager() {
        return viewPager;
    }

    private void constrainTo(Point size, Point maxSize) {
        if (maxSize.getPointX() >= 0) {
            if (size.getPointX() > maxSize.getPointX()) {
                size.modify(maxSize.getPointX(), size.getPointY());
            }
        }
        if (maxSize.getPointY() >= 0) {
            if (size.getPointY() > maxSize.getPointY()) {
                size.modify(size.getPointX(), maxSize.getPointY());
            }
        }
    }

    private void startTimer() {
        if (timer == null || viewPager == null || !timer.isStopped) {
            return;
        }
        timer.listener = mTimerHandlerListener;
        timer.removeAllEvent();
        timer.tick(0);
        timer.isStopped = false;
    }

    private void stopTimer() {
        if (timer == null || viewPager == null || timer.isStopped) {
            return;
        }
        timer.removeAllEvent();
        timer.listener = null;
        timer.isStopped = true;
    }

    @Override
    public void setInfiniteRatio(int infiniteRatio) {
        if (viewPager.getProvider() != null
                && viewPager.getProvider() instanceof UltraViewPagerAdapter) {
            ((UltraViewPagerAdapter) viewPager.getProvider()).setInfiniteRatio(infiniteRatio);
        }
    }

    public int getmAutoScrollValue() {
        return mAutoScrollValue;
    }

    public void setmAutoScrollValue(int mAutoScrollValue) {
        this.mAutoScrollValue = mAutoScrollValue;
    }

    public boolean ismInfiniteloop() {
        return mInfiniteloop;
    }

    public void setmInfiniteloop(boolean mInfiniteloop) {
        this.mInfiniteloop = mInfiniteloop;
    }

    public float getmRatio() {
        return mRatio;
    }

    public void setmRatio(float mRatio) {
        this.mRatio = mRatio;
    }

    public int getmScrollMode() {
        return mScrollMode;
    }

    public void setmScrollMode(int mScrollMode) {
        this.mScrollMode = mScrollMode;
    }

    public int getmDisableScroll() {
        return mDisableScroll;
    }

    public void setmDisableScroll(int mDisableScroll) {
        this.mDisableScroll = mDisableScroll;
    }

    public float getmMultiscreen() {
        return mMultiscreen;
    }

    public void setmMultiscreen(float mMultiscreen) {
        this.mMultiscreen = mMultiscreen;
    }

    public boolean ismAutoMeasure() {
        return mAutoMeasure;
    }

    public void setmAutoMeasure(boolean mAutoMeasure) {
        this.mAutoMeasure = mAutoMeasure;
    }

    public float getmItemRatio() {
        return mItemRatio;
    }

    public void setmItemRatio(float mItemRatio) {
        this.mItemRatio = mItemRatio;
    }
}
